home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / nos042_s / tzset.c < prev    next >
C/C++ Source or Header  |  1994-09-16  |  32KB  |  1,188 lines

  1. /****************************************************************************
  2. *    tzset.c                                                                    *
  3. *    tzset () and __isDST () replacements for Borland C++ 3.1.                *
  4. *                                                                            *
  5. *    $Id: tzset.c 1.1 93/03/07 17:07:35 ROOT_DOS Exp $
  6. *                                                                            *
  7. *    27 Feb 93    1.1        GT    From BSD ctime.c.                                *
  8. *    02 Mar 93    1.2        GT    Fix getenv () problem.                            *
  9. *****************************************************************************
  10. *    This file has been modified by Giles Todd.  These modifications are        *
  11. *    Copyright 1993 Giles Todd, 5 Brentnall Close, Warrington, WA5 1XN, UK    *
  12. *    (gt@rundart.demon.co.uk).                                                *
  13. *                                                                            *
  14. *    Giles Todd's moral rights under the Copyrights, Designs and Patents Act    *
  15. *    are asserted.                                                            *
  16. *                                                                            *
  17. *    See the University of California's copyright notice below for            *
  18. *    conditions of use and limitation of warranty.                            *
  19. *****************************************************************************
  20. *    This file may have been modified by DJ Delorie (Jan 1991).  If so,        *
  21. *    these modifications are Copyright (C) 1991 DJ Delorie, 24 Kirsten Ave,    *
  22. *    Rochester NH, 03867-2954, USA.                                            *
  23. *****************************************************************************
  24. *    Copyright (c) 1987, 1989 Regents of the University of California.        *
  25. *    All rights reserved.                                                    *
  26. *                                                                            *
  27. *    This code is derived from software contributed to Berkeley by            *
  28. *    Arthur David Olson of the National Cancer Institute.                    *
  29. *                                                                            *
  30. *    Redistribution and use in source and binary forms are permitted provided*
  31. *    that: (1) source distributions retain this entire copyright notice and    *
  32. *    comment, and (2) distributions including binaries display the following    *
  33. *    acknowledgement:  ``This product includes software developed by the        *
  34. *    University of California, Berkeley and its contributors'' in the        *
  35. *    documentation or other materials provided with the distribution and in    *
  36. *    all advertising materials mentioning features or use of this software.    *
  37. *    Neither the name of the University nor the names of its contributors may*
  38. *    be used to endorse or promote products derived from this software without*
  39. *    specific prior written permission.                                        *
  40. *    THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED    *
  41. *    WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF    *
  42. *    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.                    *
  43. *****************************************************************************
  44. *                                                                            *
  45. *    The TZ variable has the following syntax:                                *
  46. *                                                                            *
  47. *    STD offset [DST [offset] [, rule]]                                        *
  48. *                                                                            *
  49. *    (Spaces added for clarity.)                                                *
  50. *                                                                            *
  51. *                                                                            *
  52. *    Only the STD part is required.  If DST is not specified, summer time    *
  53. *    does not apply.  Uppercase and lowercase letters are allowed in the        *
  54. *    designation.  Any characters except a : (colon), digits, , (comma), -    *
  55. *    (minus), + (plus) and ASCII NULL are allowed.  STD denotes the standard    *
  56. *    time zone and DST denotes the summer time zone.                            *
  57. *                                                                            *
  58. *    <offset> indicates the value to be added to local time to equal            *
  59. *    Coordinated Universal Time (equivalent to GMT).  The <offset> part        *
  60. *    has the following format:                                                *
  61. *                                                                            *
  62. *    hh[:mm[:ss]]                                                            *
  63. *                                                                            *
  64. *    The <offset> part following the STD part is required.  If an <offset>    *
  65. *    part does not follow the DST part then summer time is assumed to be one    *
  66. *    hour ahead of standard time.  One or more digits may be used and are    *
  67. *    interpreted as a decimal integer.  The hour must be specified between 0    *
  68. *    and 24 (sic).  The mm (minutes) and ss (seconds) parts are optional.  If*
  69. *    these parts are present, they must be specified between 0 and 59.  If    *
  70. *    the <offset> part is preceded by a - (minus), the time zone is east of    *
  71. *    the Prime Meridian (Greenwich again).  If the <offset> part is not        *
  72. *    preceded by a - (minus) or is preceded by a + (plus), the time zone is    *
  73. *    assumed to be West of the Prime Meridian.                                *
  74. *                                                                            *
  75. *    The <rule> part has the following format:                                *
  76. *                                                                            *
  77. *    date/time,date/time                                                        *
  78. *                                                                            *
  79. *    The first date part describes the date when the change from standard to    *
  80. *    summer time occurs.  The second date part describes when the change from*
  81. *    summer to standard time occurs.  Each time part describes, in current    *
  82. *    local time, when the change is made.                                    *
  83. *                                                                            *
  84. *    The date part has the following format:                                    *
  85. *                                                                            *
  86. *    J<n>                                                                    *
  87. *                                                                            *
  88. *    or                                                                        *
  89. *                                                                            *
  90. *    M<m>.<n>.<d>                                                            *
  91. *                                                                            *
  92. *    J<n> indicates a Julian date.  <n> is the day of the year and has a        *
  93. *    value from 1 to 365.  Leap days are not counted.                        *
  94. *                                                                            *
  95. *    M<m>.<n>.<d> describes a month, a week and a day.  <m> is the month        *
  96. *    (1..12), <n> is the week (1..5) and <d> is the day (0..6).  Week one is    *
  97. *    the first week in the month when day <d> occurs.  Day zero is Sunday.    *
  98. *                                                                            *
  99. *    The time part has the same format as the <offset> part described above    *
  100. *    except that it can have no leading sign (- or +).  The default value of    *
  101. *    the time part is 02:00.                                                    *
  102. *                                                                            *
  103. *    For example, in the UK in 1993 the correct setting would be:            *
  104. *                                                                            *
  105. *    TZ=GMT0BST1,M3.4.0/02:00,M10.4.0/02:00                                    *
  106. *                                                                            *
  107. *    This extended syntax for TZ may cause some MS-DOS applications to work    *
  108. *    incorrectly.  If this occurs, the extended syntax may be used with the    *
  109. *    GTZ environment variable.  If the GTZ variable is present, it will take    *
  110. *    precedence over the TZ variable for the purposes of these routines.        *
  111. *                                                                            *
  112. ****************************************************************************/
  113.  
  114.  
  115. #if defined(LIBC_SCCS) && !defined(lint)
  116. static char sccsid[] = "@(#)ctime.c    5.23 (Berkeley) 6/22/90";
  117. #endif                         /* LIBC_SCCS and not lint */
  118.  
  119. /*
  120. ** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu).
  121. ** POSIX-style TZ environment variable handling from Guy Harr
  122. ** (guy@auspex.com).
  123. */
  124.  
  125. /*LINTLIBRARY*/
  126.  
  127. #include <fcntl.h>
  128. #include <time.h>
  129. #include <string.h>
  130. #include <ctype.h>
  131. #include <stdio.h>
  132. #include "tzfile.h"
  133.  
  134. #if defined (__STDC__) || defined (__BORLANDC__)
  135. #include <stdlib.h>
  136.  
  137. #define P(s)        s
  138. #define alloc_size_t    size_t
  139. #define qsort_size_t    size_t
  140. #define fread_size_t    size_t
  141. #define fwrite_size_t    size_t
  142.  
  143. #else                         /* !defined __STDC__ */
  144.  
  145. #define P(s)        ()
  146. #define const
  147. #define volatile
  148.  
  149. typedef char *genericptr_t;
  150. typedef unsigned alloc_size_t;
  151. typedef int qsort_size_t;
  152. typedef int fread_size_t;
  153. typedef int fwrite_size_t;
  154.  
  155. extern char *calloc ();
  156. extern char *malloc ();
  157. extern char *realloc ();
  158. extern char *getenv ();
  159.  
  160. #endif                         /* !defined __STDC__ */
  161.  
  162.  
  163. #define    USG_COMPAT
  164. #undef    ALTZONE
  165. #undef    ALL_STATE
  166.  
  167. #define ACCESS_MODE        O_RDONLY
  168. #define OPEN_MODE        O_RDONLY
  169.  
  170. #ifndef WILDABBR
  171. /*
  172. ** Someone might make incorrect use of a time zone abbreviation:
  173. **    1.    They might reference tzname[0] before calling tzset (explicitly
  174. **         or implicitly).
  175. **    2.    They might reference tzname[1] before calling tzset (explicitly
  176. **         or implicitly).
  177. **    3.    They might reference tzname[1] after setting to a time zone
  178. **        in which Daylight Saving Time is never observed.
  179. **    4.    They might reference tzname[0] after setting to a time zone
  180. **        in which Standard Time is never observed.
  181. **    5.    They might reference tm.TM_ZONE after calling offtime.
  182. ** What's best to do in the above cases is open to debate;
  183. ** for now, we just set things up so that in any of the five cases
  184. ** WILDABBR is used.  Another possibility:  initialize tzname[0] to the
  185. ** string "tzname[0] used before set", and similarly for the other cases.
  186. ** And another:  initialize tzname[0] to "ERA", with an explanation in the
  187. ** manual page of what this "time zone abbreviation" means (doing this so
  188. ** that tzname[0] has the "normal" length of three characters).
  189. */
  190. #define WILDABBR    "   "
  191. #endif                         /* !defined WILDABBR */
  192.  
  193. #ifndef TRUE
  194. #define TRUE        1
  195. #define FALSE        0
  196. #endif                         /* !defined TRUE */
  197.  
  198. static const char GMT[] = "GMT";
  199.  
  200. struct ttinfo
  201.     {                         /* time type information */
  202.     long tt_gmtoff;             /* GMT offset in seconds */
  203.     int tt_isdst;             /* used to set tm_isdst */
  204.     int tt_abbrind;             /* abbreviation list index */
  205.     int tt_ttisstd;             /* TRUE if transition is std time */
  206.     };
  207.  
  208. struct lsinfo
  209.     {                         /* leap second information */
  210.     time_t ls_trans;         /* transition time */
  211.     long ls_corr;             /* correction to apply */
  212.     };
  213.  
  214. struct state
  215.     {
  216.     int leapcnt;
  217.     int timecnt;
  218.     int typecnt;
  219.     int charcnt;
  220.     time_t ats[TZ_MAX_TIMES];
  221.     unsigned char types[TZ_MAX_TIMES];
  222.     struct ttinfo ttis[TZ_MAX_TYPES];
  223.     char chars[(TZ_MAX_CHARS + 1 > sizeof GMT) ?
  224.                     TZ_MAX_CHARS + 1 : sizeof GMT];
  225.     struct lsinfo lsis[TZ_MAX_LEAPS];
  226.     };
  227.  
  228. struct rule
  229.     {
  230.     int r_type;                 /* type of rule--see below */
  231.     int r_day;                 /* day number of rule */
  232.     int r_week;                 /* week number of rule */
  233.     int r_mon;                 /* month number of rule */
  234.     long r_time;             /* transition time of rule */
  235.     };
  236.  
  237. #define    JULIAN_DAY        0     /* Jn - Julian day */
  238. #define    DAY_OF_YEAR        1     /* n - day of year */
  239. #define    MONTH_NTH_DAY_OF_WEEK    2        /* Mm.n.d - month, week, day of week */
  240.  
  241. static struct rule to_dst_rule =
  242.     {
  243.     MONTH_NTH_DAY_OF_WEEK,
  244.     0, 4, 3, 2 * SECSPERHOUR
  245.     };
  246.     
  247. static struct rule to_std_rule =
  248.     {
  249.     MONTH_NTH_DAY_OF_WEEK,
  250.     0, 4, 10, 2 * SECSPERHOUR
  251.     };
  252.  
  253. static long std_off;                    /* STD offset                        */
  254. static long dst_off;                    /* DST offset                        */
  255.  
  256. /*
  257. ** Prototypes for static functions.
  258. */
  259.  
  260. static const char *getzname P ((const char *strp));
  261. static const char *getnum P ((const char *strp, int *nump, int min,
  262.                                    int max));
  263. static const char *getsecs P ((const char *strp, long *secsp));
  264. static const char *getoffset P ((const char *strp, long *offsetp));
  265. static const char *getrule P ((const char *strp, struct rule * rulep));
  266. static void gmtload P ((struct state * sp));
  267. static void settzname P ((void));
  268. static time_t transtime P ((time_t janfirst, int year,
  269.                                    const struct rule * rulep, long offset));
  270. #if    0
  271. static int tzload P ((const char *name, struct state * sp));
  272. #endif
  273. static int tzparse P ((const char *name, struct state * sp,
  274.                                int lastditch));
  275.  
  276. #ifdef ALL_STATE
  277. static struct state *lclptr;
  278. #endif                         /* defined ALL_STATE */
  279.  
  280. #ifndef ALL_STATE
  281. static struct state lclmem;
  282. #if    0
  283. static struct state gmtmem;
  284. #endif
  285.  
  286. #define lclptr        (&lclmem)
  287. #if    0
  288. #define gmtptr        (&gmtmem)
  289. #endif
  290. #endif                         /* State Farm */
  291.  
  292. static int lcl_is_set;
  293.  
  294. char _FAR * const _Cdecl tzname[2] = {
  295.                    WILDABBR,
  296.                    WILDABBR
  297.     };
  298.  
  299. #ifdef USG_COMPAT
  300. time_t timezone = 0;
  301. int daylight = 0;
  302.  
  303. #endif                         /* defined USG_COMPAT */
  304.  
  305. #ifdef ALTZONE
  306. time_t altzone = 0;
  307.  
  308. #endif                         /* defined ALTZONE */
  309.  
  310. static void
  311.      settzname ()
  312.     {
  313.     register const struct state *const sp = lclptr;
  314.     register int i;
  315.  
  316.     (void) strcpy (tzname[0], WILDABBR);
  317.     (void) strcpy (tzname[1], WILDABBR);
  318. #ifdef USG_COMPAT
  319.     daylight = 0;
  320.     timezone = 0;
  321. #endif                                             /* defined USG_COMPAT */
  322. #ifdef ALTZONE
  323.     altzone = 0;
  324. #endif                                             /* defined ALTZONE */
  325. #ifdef ALL_STATE
  326.     if (sp == NULL)
  327.         {
  328.         (void) strcpy (tzname[0], GMT);
  329.         (void) strcpy (tzname[1], GMT);
  330.         return;
  331.         }
  332. #endif                                             /* defined ALL_STATE */
  333.  
  334.     for (i = 0; i < sp->typecnt; ++i)
  335.         {
  336.         register const struct ttinfo *const ttisp = &sp->ttis[i];
  337.  
  338.         (void) strcpy (tzname[ttisp->tt_isdst],
  339.                        (char *) &sp->chars[ttisp->tt_abbrind]);
  340. #ifdef USG_COMPAT
  341.         if (ttisp->tt_isdst)
  342.             daylight = 1;
  343.  
  344.         if (i == 0 || !ttisp->tt_isdst)
  345.             timezone = -(ttisp->tt_gmtoff);
  346. #endif                                             /* defined USG_COMPAT */
  347. #ifdef ALTZONE
  348.  
  349.         if (i == 0 || ttisp->tt_isdst)
  350.             altzone = -(ttisp->tt_gmtoff);
  351. #endif                                             /* defined ALTZONE */
  352.  
  353.         }
  354.     /* * And to get the latest zone names into tzname. . . */
  355.     for (i = 0; i < sp->timecnt; ++i)
  356.         {
  357.         register const struct ttinfo *const ttisp =
  358.         &sp->ttis[sp->types[i]];
  359.  
  360.         (void) strcpy (tzname[ttisp->tt_isdst], 
  361.                        (char *) &sp->chars[ttisp->tt_abbrind]);
  362.         }
  363.     }
  364.  
  365. #if    0
  366. static int
  367.     tzload (name, sp)
  368. register const char *name;
  369. register struct state *const sp;
  370.     {
  371.     register const char *p;
  372.     register int i;
  373.     register int fid;
  374.  
  375.     if (name == NULL && (name = TZDEFAULT) == NULL)
  376.         return -1;
  377.  
  378.         {
  379.         char fullname[FILENAME_MAX + 1];
  380.  
  381.         if (name[0] == ':')
  382.             ++name;
  383.  
  384.         if (name[0] != '/')
  385.             {
  386.             if ((p = TZDIR) == NULL)
  387.                 return -1;
  388.  
  389.             if ((strlen (p) + strlen (name) + 1) >= sizeof fullname)
  390.                 return -1;
  391.  
  392.             (void) strcpy (fullname, p);
  393.             (void) strcat (fullname, "/");
  394.             (void) strcat (fullname, name);
  395.             name = fullname;
  396.             }
  397.  
  398.         if ((fid = open (name, OPEN_MODE)) == -1)
  399.             return -1;
  400.  
  401.         }
  402.         {
  403.         register const struct tzhead *tzhp;
  404.         char buf[sizeof *sp + sizeof *tzhp];
  405.         int ttisstdcnt;
  406.  
  407.         i = read (fid, buf, sizeof buf);
  408.         if (close (fid) != 0 || i < sizeof *tzhp)
  409.             return -1;
  410.  
  411.         tzhp = (struct tzhead *) buf;
  412.         ttisstdcnt = (int) detzcode (tzhp->tzh_ttisstdcnt);
  413.         sp->leapcnt = (int) detzcode (tzhp->tzh_leapcnt);
  414.         sp->timecnt = (int) detzcode (tzhp->tzh_timecnt);
  415.         sp->typecnt = (int) detzcode (tzhp->tzh_typecnt);
  416.         sp->charcnt = (int) detzcode (tzhp->tzh_charcnt);
  417.         if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
  418.             sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
  419.             sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
  420.             sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
  421.             (ttisstdcnt != sp->typecnt && ttisstdcnt != 0))
  422.             return -1;
  423.         if (i < sizeof *tzhp +
  424.             sp->timecnt * (4 + sizeof (char)) +
  425.             sp->typecnt * (4 + 2 * sizeof (char)) +
  426.             sp->charcnt * sizeof (char) +
  427.             sp->leapcnt * 2 * 4 +
  428.  
  429.             ttisstdcnt * sizeof (char))
  430.             return -1;
  431.  
  432.         p = buf + sizeof *tzhp;
  433.         for (i = 0; i < sp->timecnt; ++i)
  434.             {
  435.             sp->ats[i] = detzcode (p);
  436.             p += 4;
  437.             }
  438.  
  439.         for (i = 0; i < sp->timecnt; ++i)
  440.             {
  441.             sp->types[i] = (unsigned char) *p++;
  442.             if (sp->types[i] >= sp->typecnt)
  443.                 return -1;
  444.  
  445.             }
  446.         for (i = 0; i < sp->typecnt; ++i)
  447.             {
  448.             register struct ttinfo *ttisp;
  449.  
  450.             ttisp = &sp->ttis[i];
  451.             ttisp->tt_gmtoff = detzcode (p);
  452.             p += 4;
  453.             ttisp->tt_isdst = (unsigned char) *p++;
  454.             if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
  455.                 return -1;
  456.  
  457.             ttisp->tt_abbrind = (unsigned char) *p++;
  458.             if (ttisp->tt_abbrind < 0 ||
  459.                 ttisp->tt_abbrind > sp->charcnt)
  460.                 return -1;
  461.  
  462.             }
  463.         for (i = 0; i < sp->charcnt; ++i)
  464.             sp->chars[i] = *p++;
  465.  
  466.         sp->chars[i] = '\0';                     /* ensure '\0' at end */
  467.         for (i = 0; i < sp->leapcnt; ++i)
  468.             {
  469.             register struct lsinfo *lsisp;
  470.  
  471.             lsisp = &sp->lsis[i];
  472.             lsisp->ls_trans = detzcode (p);
  473.             p += 4;
  474.             lsisp->ls_corr = detzcode (p);
  475.             p += 4;
  476.             }
  477.  
  478.         for (i = 0; i < sp->typecnt; ++i)
  479.             {
  480.             register struct ttinfo *ttisp;
  481.  
  482.             ttisp = &sp->ttis[i];
  483.             if (ttisstdcnt == 0)
  484.                 ttisp->tt_ttisstd = FALSE;
  485.             else
  486.                 {
  487.                 ttisp->tt_ttisstd = *p++;
  488.                 if (ttisp->tt_ttisstd != TRUE &&
  489.                     ttisp->tt_ttisstd != FALSE)
  490.                     return -1;
  491.  
  492.                 }
  493.             }
  494.         }
  495.     return 0;
  496.     }
  497. #endif
  498.  
  499. static const int mon_lengths[2][MONSPERYEAR] = {
  500.                             { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
  501.                             { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
  502.     };
  503.  
  504. static const int year_lengths[2] = {
  505.                                     DAYSPERNYEAR, DAYSPERLYEAR
  506.     };
  507.  
  508. /*
  509. ** Given a pointer into a time zone string, scan until a character that is not
  510. ** a valid character in a zone name is found.  Return a pointer to that
  511. ** character.
  512. */
  513.  
  514. static const char *
  515.      getzname (strp)
  516. register const char *strp;
  517.     {
  518.     register char c;
  519.  
  520.     while ((c = *strp) != '\0' && !isdigit (c) && c != ',' && c != '-' &&
  521.            c != '+')
  522.         ++strp;
  523.  
  524.     return strp;
  525.     }
  526.  
  527. /*
  528. ** Given a pointer into a time zone string, extract a number from that string.
  529. ** Check that the number is within a specified range; if it is not, return
  530. ** NULL.
  531. ** Otherwise, return a pointer to the first character not part of the number.
  532. */
  533.  
  534. static const char *
  535.      getnum (strp, nump, min, max)
  536. register const char *strp;
  537. int *const nump;
  538. const int min;
  539. const int max;
  540.     {
  541.     register char c;
  542.     register int num;
  543.  
  544.     if (strp == NULL || !isdigit (*strp))
  545.         return NULL;
  546.  
  547.     num = 0;
  548.     while ((c = *strp) != '\0' && isdigit (c))
  549.         {
  550.         num = num * 10 + (c - '0');
  551.         if (num > max)
  552.             return NULL;                         /* illegal value */
  553.  
  554.         ++strp;
  555.         }
  556.  
  557.     if (num < min)
  558.         return NULL;                             /* illegal value */
  559.  
  560.     *nump = num;
  561.     return strp;
  562.     }
  563.  
  564. /*
  565. ** Given a pointer into a time zone string, extract a number of seconds,
  566. ** in hh[:mm[:ss]] form, from the string.
  567. ** If any error occurs, return NULL.
  568. ** Otherwise, return a pointer to the first character not part of the number
  569. ** of seconds.
  570. */
  571.  
  572. static const char *
  573.      getsecs (strp, secsp)
  574. register const char *strp;
  575. long *const secsp;
  576.     {
  577.     int num;
  578.  
  579.     strp = getnum (strp, &num, 0, HOURSPERDAY);
  580.     if (strp == NULL)
  581.         return NULL;
  582.  
  583.     *secsp = num * SECSPERHOUR;
  584.     if (*strp == ':')
  585.         {
  586.         ++strp;
  587.         strp = getnum (strp, &num, 0, MINSPERHOUR - 1);
  588.         if (strp == NULL)
  589.             return NULL;
  590.  
  591.         *secsp += num * SECSPERMIN;
  592.         if (*strp == ':')
  593.             {
  594.             ++strp;
  595.             strp = getnum (strp, &num, 0, SECSPERMIN - 1);
  596.             if (strp == NULL)
  597.                 return NULL;
  598.  
  599.             *secsp += num;
  600.             }
  601.  
  602.         }
  603.  
  604.     return strp;
  605.     }
  606.  
  607. /*
  608. ** Given a pointer into a time zone string, extract an offset, in
  609. ** [+-]hh[:mm[:ss]] form, from the string.
  610. ** If any error occurs, return NULL.
  611. ** Otherwise, return a pointer to the first character not part of the time.
  612. */
  613.  
  614. static const char *
  615.      getoffset (strp, offsetp)
  616. register const char *strp;
  617. long *const offsetp;
  618.     {
  619.     register int neg;
  620.  
  621.     if (*strp == '-')
  622.         {
  623.         neg = 1;
  624.         ++strp;
  625.         }
  626.     else
  627.     if (isdigit (*strp) || *strp++ == '+')
  628.         neg = 0;
  629.     else
  630.         return NULL;                             /* illegal offset */
  631.  
  632.     strp = getsecs (strp, offsetp);
  633.     if (strp == NULL)
  634.         return NULL;                             /* illegal time */
  635.  
  636.     if (neg)
  637.         *offsetp = -*offsetp;
  638.  
  639.     return strp;
  640.     }
  641.  
  642. /*
  643. ** Given a pointer into a time zone string, extract a rule in the form
  644. ** date[/time].  See POSIX section 8 for the format of "date" and "time".
  645. ** If a valid rule is not found, return NULL.
  646. ** Otherwise, return a pointer to the first character not part of the rule.
  647. */
  648.  
  649. static const char *
  650.      getrule (strp, rulep)
  651. const char *strp;
  652. register struct rule *const rulep;
  653.     {
  654.     if (*strp == 'J')
  655.         {
  656.         /* * Julian day. */
  657.         rulep->r_type = JULIAN_DAY;
  658.         ++strp;
  659.         strp = getnum (strp, &rulep->r_day, 1, DAYSPERNYEAR);
  660.         }
  661.     else
  662.     if (*strp == 'M')
  663.         {
  664.         /* * Month, week, day. */
  665.         rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
  666.         ++strp;
  667.         strp = getnum (strp, &rulep->r_mon, 1, MONSPERYEAR);
  668.         if (strp == NULL)
  669.             return NULL;
  670.  
  671.         if (*strp++ != '.')
  672.             return NULL;
  673.  
  674.         strp = getnum (strp, &rulep->r_week, 1, 5);
  675.         if (strp == NULL)
  676.             return NULL;
  677.  
  678.         if (*strp++ != '.')
  679.             return NULL;
  680.  
  681.         strp = getnum (strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
  682.         }
  683.     else
  684.     if (isdigit (*strp))
  685.         {
  686.         /* * Day of year. */
  687.         rulep->r_type = DAY_OF_YEAR;
  688.         strp = getnum (strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
  689.         }
  690.     else
  691.         return NULL;                             /* invalid format */
  692.  
  693.     if (strp == NULL)
  694.         return NULL;
  695.  
  696.     if (*strp == '/')
  697.         {
  698.         /* * Time specified. */
  699.         ++strp;
  700.         strp = getsecs (strp, &rulep->r_time);
  701.         }
  702.     else
  703.         rulep->r_time = 2 * SECSPERHOUR;         /* default = 2:00:00 */
  704.  
  705.     return strp;
  706.     }
  707.  
  708. /*
  709. ** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the
  710. ** year, a rule, and the offset from GMT at the time that rule takes effect,
  711. ** calculate the Epoch-relative time that rule takes effect.
  712. */
  713.  
  714. static time_t
  715.        transtime (janfirst, year, rulep, offset)
  716. const time_t janfirst;
  717. const int year;
  718. register const struct rule *const rulep;
  719. const long offset;
  720.     {
  721.     register int leapyear;
  722.     register time_t value;
  723.     register int i;
  724.     int d, m1, yy0, yy1, yy2, dow;
  725.  
  726.     leapyear = isleap (year);
  727.     switch (rulep->r_type)
  728.         {
  729.  
  730.         case JULIAN_DAY:
  731.             /* * Jn - Julian day, 1 == January 1, 60 == March 1 even in
  732.              * leap * years. * In non-leap years, or if the day number is
  733.              * 59 or less, just * add SECSPERDAY times the day number-1 to
  734.              * the time of * January 1, midnight, to get the day. */
  735.             value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
  736.             if (leapyear && rulep->r_day >= 60)
  737.                 value += SECSPERDAY;
  738.  
  739.             break;
  740.  
  741.         case DAY_OF_YEAR:
  742.             /* * n - day of year. * Just add SECSPERDAY times the day
  743.              * number to the time of * January 1, midnight, to get the day. */
  744.             value = janfirst + rulep->r_day * SECSPERDAY;
  745.             break;
  746.  
  747.         case MONTH_NTH_DAY_OF_WEEK:
  748.             /* * Mm.n.d - nth "dth day" of month m. */
  749.             value = janfirst;
  750.             for (i = 0; i < rulep->r_mon - 1; ++i)
  751.                 value += mon_lengths[leapyear][i] * SECSPERDAY;
  752.  
  753.             /* * Use Zeller's Congruence to get day-of-week of first day of *
  754.              * month. */
  755.             m1 = (rulep->r_mon + 9) % 12 + 1;
  756.             yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
  757.             yy1 = yy0 / 100;
  758.             yy2 = yy0 % 100;
  759.             dow = ((26 * m1 - 2) / 10 +
  760.                    1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
  761.             if (dow < 0)
  762.                 dow += DAYSPERWEEK;
  763.  
  764.             /* * "dow" is the day-of-week of the first day of the month. 
  765.              * Get * the day-of-month (zero-origin) of the first "dow" day
  766.              * of the * month. */
  767.  
  768.             d = rulep->r_day - dow;
  769.             if (d < 0)
  770.                 d += DAYSPERWEEK;
  771.  
  772.             for (i = 1; i < rulep->r_week; ++i)
  773.                 {
  774.                 if (d + DAYSPERWEEK >=
  775.                     mon_lengths[leapyear][rulep->r_mon - 1])
  776.                     break;
  777.  
  778.                 d += DAYSPERWEEK;
  779.                 }
  780.  
  781.             /* * "d" is the day-of-month (zero-origin) of the day we want. */
  782.             value += d * SECSPERDAY;
  783.             break;
  784.         }
  785.  
  786.     /* * "value" is the Epoch-relative time of 00:00:00 GMT on the day in *
  787.      * question.  To get the Epoch-relative time of the specified local *
  788.      * time on that day, add the transition time and the current offset *
  789.      * from GMT. */
  790.     return value + rulep->r_time + offset;
  791.     }
  792.  
  793. /*
  794. ** Given a POSIX section 8-style TZ string, fill in the rule tables as
  795. ** appropriate.
  796. */
  797.  
  798. static int
  799.     tzparse (name, sp, lastditch)
  800. const char *name;
  801. register struct state *const sp;
  802. const int lastditch;
  803.     {
  804.     const char *stdname;
  805.     const char *dstname;
  806.     int stdlen;
  807.     int dstlen;
  808.     long stdoffset;
  809.     long dstoffset;
  810.     register time_t *atp;
  811.     register unsigned char *typep;
  812.     register char *cp;
  813.     register int load_result;
  814.  
  815.     stdname = name;
  816.     if (lastditch)
  817.         {
  818.         stdlen = strlen (name);                     /* length of standard zone
  819.                                                   * name */
  820.         name += stdlen;
  821.         if (stdlen >= sizeof sp->chars)
  822.             stdlen = (sizeof sp->chars) - 1;
  823.  
  824.         }
  825.     else
  826.         {
  827.         name = getzname (name);
  828.         stdlen = (int) (name - stdname);
  829.         if (stdlen < 3)
  830.             return -1;
  831.  
  832.         }
  833.     if (*name == '\0')
  834.         return -1;
  835.     else
  836.         {
  837.         name = getoffset (name, &stdoffset);
  838.         if (name == NULL)
  839.             return -1;
  840.  
  841.         }
  842. #if    0
  843.     load_result = tzload (TZDEFRULES, sp);
  844.     if (load_result != 0)
  845. #else
  846.         load_result = 1;
  847. #endif
  848.         sp->leapcnt = 0;                         /* so, we're off a little */
  849.  
  850.     if (*name != '\0')
  851.         {
  852.         dstname = name;
  853.         name = getzname (name);
  854.         dstlen = (int) (name - dstname);         /* length of DST zone name */
  855.         if (dstlen < 3)
  856.             return -1;
  857.  
  858.         if (*name != '\0' && *name != ',' && *name != ';')
  859.             {
  860.             name = getoffset (name, &dstoffset);
  861.             if (name == NULL)
  862.                 return -1;
  863.  
  864.             }
  865.         else
  866.             dstoffset = stdoffset - SECSPERHOUR;
  867.  
  868.         std_off = stdoffset;
  869.         dst_off = dstoffset;
  870.         if (*name == ',' || *name == ';')
  871.             {
  872.             struct rule start;
  873.             struct rule end;
  874.             register int year;
  875.             register time_t janfirst;
  876.             time_t starttime;
  877.             time_t endtime;
  878.  
  879.             ++name;
  880.             if ((name = getrule (name, &start)) == NULL)
  881.                 return -1;
  882.  
  883.             to_dst_rule = start;
  884.             if (*name++ != ',')
  885.                 return -1;
  886.  
  887.             if ((name = getrule (name, &end)) == NULL)
  888.                 return -1;
  889.  
  890.             to_std_rule = end;
  891.             if (*name != '\0')
  892.                 return -1;
  893.  
  894.             sp->typecnt = 2;                     /* standard time and DST */
  895.             /* * Two transitions per year, from EPOCH_YEAR to 2037. */
  896.             sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1);
  897.             if (sp->timecnt > TZ_MAX_TIMES)
  898.                 return -1;
  899.  
  900.             sp->ttis[0].tt_gmtoff = -dstoffset;
  901.             sp->ttis[0].tt_isdst = 1;
  902.             sp->ttis[0].tt_abbrind = stdlen + 1;
  903.             sp->ttis[1].tt_gmtoff = -stdoffset;
  904.             sp->ttis[1].tt_isdst = 0;
  905.             sp->ttis[1].tt_abbrind = 0;
  906.             atp = sp->ats;
  907.             typep = sp->types;
  908.             janfirst = 0;
  909.             for (year = EPOCH_YEAR; year <= 2037; ++year)
  910.                 {
  911.                 starttime = transtime (janfirst, year, &start,
  912.                                        stdoffset);
  913.                 endtime = transtime (janfirst, year, &end,
  914.                                      dstoffset);
  915.                 if (starttime > endtime)
  916.                     {
  917.                     *atp++ = endtime;
  918.                     *typep++ = 1;                 /* DST ends */
  919.                     *atp++ = starttime;
  920.                     *typep++ = 0;                 /* DST begins */
  921.                     }
  922.                 else
  923.                     {
  924.                     *atp++ = starttime;
  925.                     *typep++ = 0;                 /* DST begins */
  926.                     *atp++ = endtime;
  927.                     *typep++ = 1;                 /* DST ends */
  928.                     }
  929.  
  930.                 janfirst +=
  931.                 year_lengths[isleap (year)] * SECSPERDAY;
  932.                 }
  933.             }
  934.         else
  935.             {
  936.             int sawstd;
  937.             int sawdst;
  938.             long stdfix;
  939.             long dstfix;
  940.             long oldfix;
  941.             int isdst;
  942.             register int i;
  943.  
  944.             if (*name != '\0')
  945.                 return -1;
  946.  
  947.             if (load_result != 0)
  948.                 return -1;
  949.             /* * Compute the difference between the real and * prototype
  950.              * standard and summer time offsets * from GMT, and put the
  951.              * real standard and summer * time offsets into the rules in
  952.              * place of the * prototype offsets. */
  953.  
  954.             sawstd = FALSE;
  955.             sawdst = FALSE;
  956.             stdfix = 0;
  957.             dstfix = 0;
  958.             for (i = 0; i < sp->typecnt; ++i)
  959.                 {
  960.                 if (sp->ttis[i].tt_isdst)
  961.                     {
  962.                     oldfix = dstfix;
  963.                     dstfix =
  964.                     sp->ttis[i].tt_gmtoff + dstoffset;
  965.                     if (sawdst && (oldfix != dstfix))
  966.                         return -1;
  967.  
  968.                     sp->ttis[i].tt_gmtoff = -dstoffset;
  969.                     sp->ttis[i].tt_abbrind = stdlen + 1;
  970.                     sawdst = TRUE;
  971.                     }
  972.                 else
  973.                     {
  974.                     oldfix = stdfix;
  975.                     stdfix =
  976.                     sp->ttis[i].tt_gmtoff + stdoffset;
  977.                     if (sawstd && (oldfix != stdfix))
  978.                         return -1;
  979.  
  980.                     sp->ttis[i].tt_gmtoff = -stdoffset;
  981.                     sp->ttis[i].tt_abbrind = 0;
  982.                     sawstd = TRUE;
  983.                     }
  984.                 }
  985.  
  986.             /* * Make sure we have both standard and summer time. */
  987.             if (!sawdst || !sawstd)
  988.                 return -1;
  989.             /* * Now correct the transition times by shifting * them by the
  990.              * difference between the real and * prototype offsets.  Note
  991.              * that this difference * can be different in standard and
  992.              * summer time; * the prototype probably has a 1-hour
  993.              * difference * between standard and summer time, but a
  994.              * different * difference can be specified in TZ. */
  995.  
  996.             isdst = FALSE;                         /* we start in standard time */
  997.             for (i = 0; i < sp->timecnt; ++i)
  998.                 {
  999.                 register const struct ttinfo *ttisp;
  1000.  
  1001.                 /* * If summer time is in effect, and the * transition time
  1002.                  * was not specified as * standard time, add the summer
  1003.                  * time * offset to the transition time; * otherwise, add
  1004.                  * the standard time offset * to the transition time. */
  1005.                 ttisp = &sp->ttis[sp->types[i]];
  1006.                 sp->ats[i] +=
  1007.                 (isdst && !ttisp->tt_ttisstd) ?
  1008.                 dstfix : stdfix;
  1009.                 isdst = ttisp->tt_isdst;
  1010.                 }
  1011.             }
  1012.         }
  1013.     else
  1014.         {
  1015.         dstlen = 0;
  1016.         sp->typecnt = 1;                         /* only standard time */
  1017.         sp->timecnt = 0;
  1018.         sp->ttis[0].tt_gmtoff = -stdoffset;
  1019.         sp->ttis[0].tt_isdst = 0;
  1020.         sp->ttis[0].tt_abbrind = 0;
  1021.         }
  1022.  
  1023.     sp->charcnt = stdlen + 1;
  1024.     if (dstlen != 0)
  1025.         sp->charcnt += dstlen + 1;
  1026.  
  1027.     if (sp->charcnt > sizeof sp->chars)
  1028.         return -1;
  1029.  
  1030.     cp = sp->chars;
  1031.     (void) strncpy (cp, stdname, stdlen);
  1032.     cp += stdlen;
  1033.     *cp++ = '\0';
  1034.     if (dstlen != 0)
  1035.         {
  1036.         (void) strncpy (cp, dstname, dstlen);
  1037.         *(cp + dstlen) = '\0';
  1038.         }
  1039.  
  1040.     return 0;
  1041.     }
  1042.  
  1043. static void
  1044.      gmtload (sp)
  1045. struct state *const sp;
  1046.     {
  1047. #if    0
  1048.     if (tzload (GMT, sp) != 0)
  1049. #endif
  1050.         (void) tzparse (GMT, sp, TRUE);
  1051.  
  1052.     }
  1053.  
  1054. void _FARFUNC
  1055.      tzset ()
  1056.     {
  1057.     register const char *name;
  1058.     void tzsetwall ();
  1059.  
  1060.     name = getenv ("GTZ");
  1061.     if (name == NULL)
  1062.         {
  1063.         name = getenv ("TZ");
  1064.         if (name == NULL)
  1065.             {
  1066. #if 0
  1067.             tzsetwall ();
  1068.             return;
  1069. #else
  1070.             name = "EST5";
  1071. #endif
  1072.             }
  1073.  
  1074.         }
  1075.  
  1076.     lcl_is_set = TRUE;
  1077. #ifdef ALL_STATE
  1078.     if (lclptr == NULL)
  1079.         {
  1080.         lclptr = (struct state *) malloc (sizeof *lclptr);
  1081.         if (lclptr == NULL)
  1082.             {
  1083.             settzname ();                         /* all we can do */
  1084.             return;
  1085.             }
  1086.  
  1087.         }
  1088. #endif                                             /* defined ALL_STATE */
  1089.  
  1090.     if (*name == '\0')
  1091.         {
  1092.         /* * User wants it fast rather than right. */
  1093.         lclptr->leapcnt = 0;                     /* so, we're off a little */
  1094.         lclptr->timecnt = 0;
  1095.         lclptr->ttis[0].tt_gmtoff = 0;
  1096.         lclptr->ttis[0].tt_abbrind = 0;
  1097.         (void) strcpy (lclptr->chars, GMT);
  1098.         }
  1099.     else /* if (tzload (name, lclptr) != 0) */
  1100.         if (name[0] == ':' || tzparse (name, lclptr, FALSE) != 0)
  1101.             (void) gmtload (lclptr);
  1102.  
  1103.     settzname ();
  1104.     }
  1105.  
  1106. void
  1107.      tzsetwall ()
  1108.     {
  1109.          lcl_is_set = TRUE;
  1110. #ifdef ALL_STATE
  1111.     if (lclptr == NULL)
  1112.         {
  1113.         lclptr = (struct state *) malloc (sizeof *lclptr);
  1114.         if (lclptr == NULL)
  1115.             {
  1116.             settzname ();                         /* all we can do */
  1117.             return;
  1118.             }
  1119.  
  1120.         }
  1121. #endif                                             /* defined ALL_STATE */
  1122.  
  1123. #if    0
  1124.     if (tzload ((char *) NULL, lclptr) != 0)
  1125. #endif
  1126.         gmtload (lclptr);
  1127.  
  1128.     settzname ();
  1129.     }
  1130.  
  1131. #pragma startup tzset 30
  1132.  
  1133. /****************************************************************************
  1134. *    __isDST                                                                    *
  1135. *    Determines whether daylight savings time is in effect.                    *
  1136. *    Returns non-zero if daylight savings time is in effect for the given    *
  1137. *    date.  If <month> is zero, <yday> is the day of the year else <yday>    *
  1138. *    is the day of the month.  <yday> is zero based.  Assumption: tzset ()    *
  1139. *    has previously been called.                                                *
  1140. ****************************************************************************/
  1141.  
  1142. int pascal near __isDST (unsigned hour, unsigned yday,
  1143.                          unsigned month, unsigned year)
  1144.     {
  1145.     time_t lhour;                        /* hour (long)                        */
  1146.     time_t lyday;                        /* day (long)                        */
  1147.     time_t lyear;                        /* year (long)                        */
  1148.     time_t year_start;                    /* epoch relative start of year        */
  1149.     time_t now;                            /* epoch relative parameters        */
  1150.     time_t dst_start;                    /* start of DST                        */
  1151.     time_t std_start;                    /* start of STD                        */
  1152.     static unsigned long month_day[] =
  1153.         { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
  1154.  
  1155.     /* Calculate the start of the year. */
  1156.  
  1157.     lhour = (time_t) hour;
  1158.     lyday = (time_t) yday;
  1159.     lyear = (time_t) year;
  1160.     year_start = (((lyear + 2L) / 4L) +
  1161.                   (lyear * DAYSPERNYEAR)) * 24L * 60L * 60L;
  1162.  
  1163.     /* Get the DST and STD start times. */
  1164.  
  1165.     dst_start = transtime (year_start, year + 1970, &to_dst_rule, std_off);
  1166.     std_start = transtime (year_start, year + 1970, &to_std_rule, dst_off);
  1167.  
  1168.     /* Calculate now. */
  1169.  
  1170.     if (month == 0)
  1171.         now = year_start +
  1172.               (lyday * 24L * 60L * 60L) +
  1173.               (lhour * 60L * 60L);
  1174.     else
  1175.         now = year_start +
  1176.               (month_day[month - 1] * 24L * 60L * 60L) +
  1177.               (lyday * 24L * 60L * 60L) +
  1178.               (lhour * 60L * 60L);
  1179.  
  1180.     /* Are we in DST? */
  1181.  
  1182.     if (now < dst_start || now >= std_start)
  1183.         return (0);
  1184.  
  1185.     return (1);
  1186.     }    /* int pascal __isDST (unsigned hour, unsigned yday,
  1187.                                 unsigned month, unsigned year) */
  1188.